import gzip
import json
from math import atan2, degrees, pi, floor
from collections import OrderedDict
# import hashlib

# type_join_2

types_file = './test/action.goyoo.types.log' # this programme will generate this
joined_file = './test/action.goyoo.joined.log.gz' # we need this as a pre

type_map = {}
type_map2 = {}
type_map3 = {}
type_hash = {}

pos_type_set = set([
    'click',
    'dblclick',
    'select',
    'resize',
    'scroll',
    'keydown_fn',
    'keyup_fn',
    'keyup_letter',
    'keydown_letter',
    'keyup_num',
    'keydown_num',
])


def process(line):
    amsg = json.loads(line)
    phases = amsg['data']
    num_phases = len(phases)
    total_time = phases[-1]['time']
    if num_phases < 5:
        return

    # types_set = set([])
    types = []
    types2 = []
    types3 = []
    for i in range(num_phases):
        aphase = phases[i]
        t = aphase['type']

        # skip click without mousemove
        if (t == 'click') or (t == 'dblclick'):
            nomousemove = True
            for _t in types:
                if _t.startswith('mousemove'):
                    nomousemove = False
            if nomousemove == True:
                return

        # mousemove zone (repeated mousemoves are ok)
        if i > 0 and (t == 'mousemove') and (types[-1].startswith('mousemove')):
            pphase = phases[i - 1]
            delta_y = aphase['y'] - pphase['y']
            delta_x = aphase['x'] - pphase['x']
            rads = atan2(-delta_y, delta_x)
            rads %= 2 * pi
            degs = degrees(rads)
            zone = str(int(floor(degs / 45)))
            t += zone

        # keyboard area
        if (t == 'keydown') or (t == 'keyup'):
            if (48 <= aphase['key'] <= 57) or (96 <= aphase['key'] <= 105):
                t += '_num'
            elif 65 <= aphase['key'] <= 90:
                t += '_letter'
            else:
                t += '_fn'

        # remove repeated actions (except for mousemoves as shown before)
        if i > 0 and t == types[-1]:
            # print("repeated")
            continue

        types.append(t)
        # types_set.add(t)

    if len(types) < 5:
        return

    # if len(pos_type_set & types_set) == 0:
    #     if total_time < 30000:
    #         return

    # hash_value = hashlib.sha1(''.join(types)).hexdigest()
    # if hash_value in type_hash:
    #     print type_hash[hash_value]
    #     return
    # type_hash[hash_value] = {
    #     'pgid': msgs['pgid'],
    #     'types': types,
    #     'chid': data[0]['chid'],
    # }


    for i, t in enumerate(types):
        if t in type_map:
            type_map[t] += 1
        else:
            type_map[t] = 1

        if i > 0:
            type2 = types[i - 1] + ":" + t
            types2.append(type2)
            if type2 in type_map2:
                type_map2[type2] += 1
            else:
                type_map2[type2] = 1

        if i > 1:
            type3 = types[i - 2] + ":" + types[i - 1] + ":" + t
            types3.append(type3)
            if type3 in type_map3:
                type_map3[type3] += 1
            else:
                type_map3[type3] = 1

    with open(types_file, "a+") as f:
        f.write(json.dumps({
            'pgid': amsg['pgid'],
            'types': types,
            'total_time': total_time,
            'chid': phases[0]['chid'],
        }) + '\n')

def sortMap(type_map):
    orderDict = OrderedDict()
    for kv in sorted(type_map.items(), key=lambda x: -x[1]):
        orderDict[kv[0]] = kv[1]
    return orderDict

def save2json(type_map, filename):
    orderDict = sortMap(type_map)
    with open(filename, "wb") as f:
        ga = json.dumps(orderDict, indent=4)
        f.write(ga.encode())


open(types_file, 'w').close()

with gzip.open(joined_file, 'r') as f:
    i = 1
    for line in f:
        process(line.decode())
        i += 1
        # if i == 100:
        #     break

    save2json(type_map, 'ttype_map.json')
    save2json(type_map2, 'ttype_map2.json')
    save2json(type_map3, 'ttype_map3.json')
